import * as d3 from "d3";
import Weather, { weathers } from "../../domains/weather";
import { useEffect, useRef, useState } from "react";

interface Props {
  metric: string;
}

const Histogram = ({ metric }: Props) => {
  const wrapper = useRef(null);
  const bounds = useRef(null);
  const binsGroup = useRef(null);
  const xAxis = useRef(null);
  const xAxisLable = useRef(null);
  const tooltip = useRef(null);

  const [tooltips, setTips] = useState("");

  const width = 600; // We will be generating many of these, so let's keep our chart small

  const dimensions = {
    // NOTE: Histograms are easier to read when they are wider than they are tall
    width: width,
    height: width * 0.9,
    // Leave a larger margin on the top to account for the bar labels which will be positioned above each bar
    margins: {
      top: 30,
      right: 10,
      bottom: 50,
      left: 50,
    },
    boundedWidth: 0,
    boundedHeight: 0,
  };
  dimensions.boundedWidth =
    dimensions.width - dimensions.margins.left - dimensions.margins.right;
  dimensions.boundedHeight =
    dimensions.height - dimensions.margins.top - dimensions.margins.bottom;

  const xAccessor = (weather: Weather) => weather[metric];

  const histogram = d3.bin<Weather, number>().value(xAccessor).thresholds(12);
  const bins = histogram(weathers);

  const xScale = d3
    .scaleLinear()
    .domain([bins[0].x0 as number, bins[bins.length - 1].x1 as number])
    .range([0, dimensions.boundedWidth])
    .nice();

  const yAccessor = (bin: d3.Bin<Weather, number>) => bin.length;
  const max = d3.max<d3.Bin<Weather, number>, number>(
    bins,
    yAccessor
  ) as number;
  const yScale = d3
    .scaleLinear()
    .domain([0, max])
    .range([dimensions.boundedHeight, 0])
    .nice();

  const mean = d3.mean(weathers, xAccessor);

  const barPadding = 1;

  useEffect(
    () => void d3.select(xAxis.current).call(d3.axisBottom(xScale)),
    [xAxis, xScale]
  );

  function showTooltip(
    e: React.MouseEvent<SVGRectElement, MouseEvent>,
    d: d3.Bin<Weather, number>,
    i: number,
    color: string
  ) {
    e.currentTarget.setAttribute("fill", color);
    setTips(metric + ":" + d.x0 + "-" + d.x1 + " " + d.length + "days");
    tooltip.current.setAttribute("opacity", 1);

    // const xPositionOfBarInChart = xScale(d.x0 as number);
    // const widthOfBarInChart = xScale(d.x1 as number) - xScale(d.x0 as number);
    // const boundsMarginOfShiftToRight = dimensions.margins.left;
    // const x =
    //   xPositionOfBarInChart +
    //   widthOfBarInChart / 2 +
    //   boundsMarginOfShiftToRight;
    // const yPositionOfBarInChart = yScale(yAccessor(d));
    // const boundsMarginOfShiftDown = dimensions.margins.top;
    // const y = yPositionOfBarInChart + boundsMarginOfShiftDown;

    // // tooltip.current.setAttribute(
    // //   "transform",
    // //   `translate(calc(-50% + ${x}px), calc(-100% + ${y}px))`
    // // );
    // tooltip.current.setAttribute("value", metric);
    // tooltip.current.setAttribute("font-size", "20");
    // // Now that we have styled our tooltip, it's time to display it to the user
    // tooltip.current.setAttribute("opacity", 1);
  }

  function hideTooltip(e: React.MouseEvent<SVGRectElement, MouseEvent>) {
    e.currentTarget.setAttribute("fill", "cornflowerblue");
    tooltip.current.setAttribute("opacity", 0);
  }

  return (
    <div>
      <svg
        key={metric}
        ref={wrapper}
        width={dimensions.width}
        height={dimensions.height}
      >
        <g
          ref={bounds}
          transform={`translate(${dimensions.margins.left},${dimensions.margins.top})`}
        >
          <g
            ref={xAxis}
            transform={`translate(0,${dimensions.boundedHeight})`}
          ></g>
          <g ref={xAxisLable}>
            <text
              fontSize={20}
              x={dimensions.boundedWidth / 2}
              y={dimensions.height - dimensions.margins.bottom + 10}
              textAnchor="middle"
            >
              {metric}
            </text>
          </g>
          <text ref={tooltip} opacity={0}>
            {tooltips}
          </text>
          <g ref={binsGroup} className="bin">
            {bins.map((d, i) => (
              <g key={"g" + i}>
                <rect
                  key={i}
                  x={xScale(d.x0 as number) + barPadding / 2}
                  y={yScale(yAccessor(d))}
                  width={d3.max([0, xScale(d.x1) - xScale(d.x0) - barPadding])}
                  height={dimensions.boundedHeight - yScale(yAccessor(d))}
                  fill="cornflowerblue"
                  onMouseEnter={(
                    e: React.MouseEvent<SVGRectElement, MouseEvent>
                  ) => {
                    showTooltip(e, d, i, "green");
                  }}
                  onMouseOut={(e) => {
                    hideTooltip(e);
                  }}
                ></rect>
                <text
                  key={"ct" + i}
                  x={
                    xScale(d.x0 as number) +
                    (xScale(d.x1 as number) - xScale(d.x0 as number)) / 2
                  }
                  y={yScale(yAccessor(d)) - 5}
                  fontSize={12}
                  textAnchor="middle"
                  fill="darkgrey"
                  fontFamily="sans-serif"
                >
                  {yAccessor(d)}
                </text>
              </g>
            ))}
            <line
              x1={xScale(mean)}
              x2={xScale(mean)}
              y1={15}
              y2={dimensions.boundedHeight}
              stroke="maroon"
              strokeDasharray={"2px 4px"}
            ></line>
            <text x={xScale(mean)} y={5} fill="maroon" textAnchor="middle">
              mean
            </text>
          </g>
        </g>
      </svg>
    </div>
  );
};

export default Histogram;
